package me.yricky.kaguya.dsl

import me.yricky.kaguya.base.*
import me.yricky.kaguya.base.lu.Joint


internal fun ModuleScope.checkSignalNameNotExist(name:String){
    assert(_inputs[name] == null){ "\"$name\"已经在模块的输入信号中存在" }
    assert(_outputs[name] == null){ "\"$name\"已经在模块的输出信号中存在" }
    assert(_innerSignals[name] == null){ "\"$name\"已经在模块的内部信号中存在" }
}

internal fun ModuleScope.checkSignalNameNotExported(name:String){
    assert(_inputs[name] == null){ "\"$name\"已经在模块的输入信号中存在" }
    assert(_outputs[name] == null){ "\"$name\"已经在模块的输出信号中存在" }
    assert(_innerSignals[name] != null){ "\"$name\"已经在模块的内部信号中存在" }
}



fun ModuleScope.inputWire(name:String,width:Int = 1):NamedWire{
    checkSignalNameNotExist(name)
    val wire = NamedWire(name,width)
    _inputs[name] = wire
    return wire
}

fun ModuleScope.wire(name:String,width:Int = 1):NamedWire{
    checkSignalNameNotExist(name)
    val wire = NamedWire(name,width)
    _innerSignals[name] = wire
    return wire
}

fun ModuleScope.reg(name:String,width:Int = 1):Reg{
    checkSignalNameNotExist(name)
    val reg = Reg(name,width)
    _innerSignals[name] = reg
    return reg
}

fun ModuleScope.outputWire(name:String,width:Int = 1):NamedWire{
    checkSignalNameNotExist(name)
    val wire = NamedWire(name,width)
    _outputs[name] = wire
    return wire
}

fun ModuleScope.outputReg(name:String,width:Int = 1):Reg{
    checkSignalNameNotExist(name)
    val reg = Reg(name,width)
    _outputs[name] = reg
    return reg
}

fun Number.bitWidth():Int{
    var width = 0
    var tmp = toLong()
    if(tmp == 0L){
        return 1
    }
    while (tmp > 0){
        width++
        tmp /= 2
    }
    return width
}

fun h(value:Number, width: Int = value.bitWidth()):ConstSignal = ConstSignal(width, value, ConstSignal.Hex)
fun d(value:Number, width: Int = value.bitWidth()):ConstSignal = ConstSignal(width, value, ConstSignal.Dec)

fun ModuleScope.joint(vararg signals: Signal):ExpressionWire{
    return Joint(signals.toList()).also {
        _logicUnits.add(it)
    }.wire
}
fun ModuleScope.joint(signals: List<Signal>):ExpressionWire{
    return Joint(signals).also {
        _logicUnits.add(it)
    }.wire
}

